package com.example.springboottest.util;

import com.example.springboottest.bean.util.IsoConfigInfoPO;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.io.StringWriter;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

import static jdk.internal.org.objectweb.asm.util.Printer.TYPES;

/**
 * @Author LiuYiShuo
 * @DATE 2023/6/15 15:40
 * @Version 1.0
 * @Description
 */
public class xsdTOXml {


    public static void main(String[] args) {

        try {

            Process exec = Runtime.getRuntime().exec("xjc -p packageName c;/Operator1.xscade");
            System.out.println(exec);

            //  xscade格式文件怎么转化成mxgraph的xml格式

            // 冒泡排序
             int[] array = {5, 2, 8, 3, 1};
             int temp;
             for(int i=0; i<array.length-1; i++){
                 for(int j=0; j<array.length-1-i; j++){
                     if(array[j] > array[j+1]){
                         temp = array[j];
                         array[j] = array[j+1];
                         array[j+1] = temp;
                     }
                 }
             }

             // file文件转成MultipartFile的步骤











        }catch (Exception e){
            e.fillInStackTrace();
        }

    }

    public static List<IsoConfigInfoPO> generateBean(List<String> classes) throws Exception {
        List<IsoConfigInfoPO> infoPOList = new ArrayList<>();
        for (String aClass : classes) {
            if (aClass.contains("ObjectFactory")) {
                String packageNm = aClass.substring(aClass.indexOf("pacs"), aClass.lastIndexOf(".")).replace("_", ".");
                Class cls = Thread.currentThread().getContextClassLoader().loadClass(aClass);
                Object factory = cls.getDeclaredConstructor().newInstance();
                for (Method method : cls.getDeclaredMethods()) {
                    if (method.getName().equals("createDocument") && method.getGenericParameterTypes().length == 0) {
                        Object doc = method.invoke(factory);
                        //生成Document根节点对象，并深度赋值所有属性以及属性的属性，递归
                        deepAssign(doc, doc.getClass());
                        XmlMapper xmlMapper = new XmlMapper();
                        //使用jaxb解析document对象为xml
                        JsonNode rootNood = xmlMapper.readTree(createXML(doc.getClass(), doc, packageNm));
                        Map.Entry<String, JsonNode> root = rootNood.fields().next();
                        //解析xml，并生成java bean
                        infoPOList.addAll(deal(root.getValue(), null, null, root.getKey(), 1, packageNm));
                    }
                }
            }
        }
        return infoPOList;
    }

    /**
     * 初始化对象以及对象的属性，并递归属性的属性，直到均初始化完毕
     *
     * @param obj 顶级对象
     * @param cls 顶级对象的class
     * @throws Exception
     */
    private static void deepAssign(Object obj, Class cls) throws Exception {
        for (Field declaredField : cls.getDeclaredFields()) {
            Class filedType = declaredField.getType();
            boolean isArray = false;
            Class c = null;
            Object o = null;
            for (Method method : cls.getDeclaredMethods()) {
                String methodName = method.getName();
                Type[] types = method.getGenericParameterTypes();
                //set方法
                if (types.length == 1) {
                    //名字类型匹配上
                    if (types[0].equals(filedType) && methodName.substring(3).equalsIgnoreCase(declaredField.getName())) {
                        //不是枚举类和抽象类
                        if (!Modifier.isAbstract(((Class) types[0]).getModifiers()) && !((Class) types[0]).isEnum()) {
                            //不是包装和基本的
                            if (Arrays.stream(TYPES).noneMatch(str -> str.contains(declaredField.getType().getName()))) {
                                o = filedType.getDeclaredConstructor().newInstance();
                                method.invoke(obj, o);
                            } else {
                                method.invoke(obj, setDefault(filedType.getName()));
                            }
                        } else {
                            Class tmpCls = ((Class) types[0]);
                            if (tmpCls.isEnum()) {
                                method.invoke(obj, tmpCls.getEnumConstants()[0]);
                                //W3C XML Schema 标准定义了以 XML 格式指定日期的明确规则。
                            } else if (tmpCls.getName().contains("XMLGregorianCalendar")) {


                                LocalDate localDate = LocalDate.now();
                                XMLGregorianCalendar xmlGregorianCalendar =
                                        DatatypeFactory.newInstance().newXMLGregorianCalendar(localDate.toString());
                                method.invoke(obj, xmlGregorianCalendar);
                            } else if (tmpCls.isArray()) {
                                Class elementType = tmpCls.getComponentType();
                                if (elementType.isPrimitive()) {
                                    methodName = methodName.substring(3);
                                    if (methodName.equalsIgnoreCase(declaredField.getName())) {
                                        method.invoke(obj, Array.newInstance(elementType,1));
                                    }
                                }
                            }
                        }
                    }
                } else {
                    //判断list/map/set 他们都是接口类型
                    if (filedType.isInterface()) {
                        if (methodName.startsWith("get")) {
                            methodName = methodName.substring(3);
                            if (methodName.equalsIgnoreCase(declaredField.getName())) {
                                Object tmp = method.invoke(obj);
                                //获取集合的元素类型
                                ParameterizedType type = (ParameterizedType) declaredField.getGenericType();
                                Type type1 = type.getActualTypeArguments()[0];
                                if (Arrays.stream(TYPES).noneMatch(str -> str.contains(type1.getTypeName()))) {
                                    //初始化元素，并添加到集合中，以便继续递归
                                    c = (Class) type1;
                                    o = c.getDeclaredConstructor().newInstance();
                                    if (tmp.getClass().getName().contains("List")) {
                                        ArrayList arrayList = (ArrayList) tmp;
                                        arrayList.add(o);
                                        isArray = true;
                                    }
                                }else {
                                    ArrayList arrayList = (ArrayList) tmp;
                                    arrayList.add(setDefault(type1.getTypeName()));
                                }
                            }
                        }
                    }


                }
            }
            if (Arrays.stream(TYPES).noneMatch(str -> str.contains(declaredField.getType().getName()))) {
                if ((!Modifier.isAbstract(filedType.getModifiers()) && !declaredField.getType().isEnum()) || isArray) {
                    deepAssign(o, c != null ? c : declaredField.getType());
                }
            }
        }
    }

    /**
     * 赋值默认值，必须按照正确的模式
     *
     * @param name 根据输入的class name名匹配
     * @return
     */
    private static Object setDefault(String name) {
        Object res = "123";
        switch (name) {
            case "java.lang.Integer":
                res = 0;
                break;
            case "java.lang.Object":
                res = null;
                break;
            case "java.lang.Double":
                res = 0.0D;
                break;
            case "java.lang.Float":
                res = 0.0F;
                break;
            case "java.lang.Short":
                res = 0;
                break;
            case "java.lang.Byte":
                res = 0;
                break;
            case "java.lang.Boolean":
                res = true;
                break;
            case "java.lang.Character":
                res = '0';
                break;
            case "java.math.BigDecimal":
                res = new BigDecimal(0);
                break;
            case "int":
                res = 0;
                break;
            case "double":
                res = 0;
                break;
            case "long":
                res = 0;
                break;
            case "short":
                res = 0;
                break;
            case "byte":
                res = 0;
                break;
            case "boolean":
                res = true;
                break;
            case "char":
                res = 0;
                break;
            case "float":
                res = 0;
                break;
            default:
        }
        return res;
    }


    /**
     * 由java bean 创建生成xml
     *
     * @param entityClass
     * @param entity
     * @param type
     * @param <T>
     * @return
     */
    public static <T> String createXML(Class entityClass, Object entity, String type) {
        StringWriter writer = new StringWriter();
        try {
            JAXBContext context = JAXBContext.newInstance(entityClass);
            try {
                QName qName = new QName("urn:iso:std:iso:20022:tech:xsd:" + type, "Document");
                JAXBElement root = new JAXBElement(qName, entityClass, entity);
                Marshaller mar = context.createMarshaller();
                mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                mar.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                mar.marshal(root, writer);
                System.out.println(writer);
            } catch (JAXBException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return writer.toString();
    }


    /**
     * 递归处理xml数据生成最终的IsoPacsConfig对象返回
     *
     * @param rootNode   要处理的node节点
     * @param rootName   根节点，目前这里是head and body
     * @param parentName 父节点
     * @param topName    根节点
     * @param deep       深度
     * @param type       版本
     * @return
     */
    private static List<IsoConfigInfoPO> deal(JsonNode rootNode, String rootName, String parentName, String topName, Integer deep, String type) {
        List<IsoConfigInfoPO> res = new ArrayList<>();
        String key;

        if (rootNode.isContainerNode()) {
            Iterator<Map.Entry<String, JsonNode>> iterator = rootNode.fields();
            String rotName = rootName;
            deep++;
            while (iterator.hasNext()) {
                Map.Entry<String, JsonNode> next = iterator.next();
                key = next.getKey();
                if (deep == 2) {
                    rotName = key;
                }
                if (next.getValue().isContainerNode()) {
                    //保存这一层父路径
                    res.add(create(key, parentName, rotName, deep, topName, type));
                    res.addAll(deal(next.getValue(), rotName, key, topName, deep, type));
                } else {
                    res.add(create(key, parentName, rootName, deep, topName, type));
                }
            }
        } else {
            key = rootName;
            res.add(create(key, parentName, rootName, deep, topName, type));
        }
        return res;
    }

    /**
     * 生成一个pacs对象
     *
     * @param routeId
     * @param parentName
     * @param rootName
     * @param deep
     * @param topName
     * @return
     */
    private static IsoConfigInfoPO create(String routeId, String parentName, String rootName, int deep, String topName, String type) {
        IsoConfigInfoPO configInfoPo = new IsoConfigInfoPO();
        configInfoPo.setRouteid(routeId);
        configInfoPo.setParentNode(parentName);
        configInfoPo.setRootNode(rootName);
        configInfoPo.setIsDelete(0);
        configInfoPo.setDeepRow(deep);
        configInfoPo.setTopRoot(topName);
        configInfoPo.setType(type);
        configInfoPo.setCreateUser("system");
        return configInfoPo;
    }





}
